package org.domain.sigepac.session;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import org.domain.sigepac.Utils;
import org.domain.sigepac.Entity.Aluno;
import org.domain.sigepac.Entity.Cidade;
import org.domain.sigepac.Entity.Cor;
import org.domain.sigepac.Entity.Curso;
import org.domain.sigepac.Entity.Sexo;
import org.domain.sigepac.Entity.Turma;
import org.domain.sigepac.Entity.Voluntario;
import org.domain.sigepac.repository.RepositorioCurso;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.datamodel.DataModel;

@Name("relatorioCurso")
@Scope(ScopeType.CONVERSATION)
public class RelatorioCurso {

	@In
	private RepositorioCurso repositorioCurso;

	@DataModel
	private List<InfoCurso> infoCursos;

	private Integer quantidadeCursos=0;
	private Integer quantidadeTurmas=0;
	private Integer quantidadeCidades=0;
	private Integer quantidadeAlunos=0;
	private Integer quantidadeVoluntarios=0;

	@In(required = false)
	@Out(required = false)
	private Date inicio;

	@In(required = false)
	@Out(required = false)
	private Date fim;


	@Factory("infoCursos")
	public void listarCursos(){

			infoCursos=new ArrayList<InfoCurso>();
			List<Curso> cursos=repositorioCurso.listar();

			for(Curso curso:cursos){

				if(!Utils.isInside(curso.getDataCriacao(),inicio, fim) )
					continue;

				InfoCurso infoCurso=new InfoCurso(curso);
				Set<Turma> turmas=curso.getTurmas();
				for(Turma turma: turmas){

					if(!turma.isAtivo())
						continue;

					if(!Utils.isInside(turma.getDataCriacao(),inicio, fim) )
						continue;

					Set<Aluno> alunos=turma.getAlunos();

					InfoCidade cidade= infoCurso.getHashCidades().get(turma.getCidade());

					for(Aluno aluno:alunos){

						cidade.add(turma,aluno);

					}

					Set<Voluntario> voluntarios=turma.getVoluntarios();

					for(Voluntario voluntario:voluntarios){
						if(voluntario.isDesligado())
							continue;

						cidade.add(turma,voluntario);
					}

					quantidadeAlunos+=alunos.size();
					quantidadeVoluntarios+=voluntarios.size();

				}

				infoCursos.add(infoCurso);
				quantidadeTurmas+=turmas.size();
				quantidadeCidades+=infoCurso.getCidades().size();
				quantidadeCursos++;
			}

	}

	public Date getInicio() {
		return inicio;
	}
	public void setInicio(Date inicio) {
		this.inicio = inicio;
	}
	public Date getFim() {
		return fim;
	}
	public void setFim(Date fim) {
		this.fim = fim;
	}

	public String getDataInicial(){
		return Utils.formataData(inicio, "dd/MM/yyyy");
	}

	public String getDataFinal(){
		return Utils.formataData(fim, "dd/MM/yyyy");
	}

	public Integer getQuantidadeAlunos() {
		return quantidadeAlunos;
	}
	public Integer getQuantidadeCidades() {
		return quantidadeCidades;
	}
	public Integer getQuantidadeCursos() {
		return quantidadeCursos;
	}

	public Integer getQuantidadeTurmas() {
		return quantidadeTurmas;
	}

	public Integer getQuantidadeVoluntarios() {
		return quantidadeVoluntarios;
	}

	public class InfoCurso{

		private Curso curso;
		private List<InfoCidade> cidades=new ArrayList<InfoCidade>();
		private HashMap<Cidade, InfoCidade> hashCidades=new HashMap<Cidade, InfoCidade>();
		public InfoCurso(Curso curso) {
			this.curso=curso;
			Set<Cidade> cidades=curso.getCidades();

			for(Cidade cidade:cidades){
				InfoCidade infoCidade=new InfoCidade(cidade);
				this.cidades.add(infoCidade);
				hashCidades.put(cidade, infoCidade);
			}

		}


		public List<InfoCidade> getCidades() {
			return cidades;
		}
		public void setCidades(List<InfoCidade> cidades) {
			this.cidades = cidades;
		}

		public Curso getCurso() {
			return curso;
		}

		public HashMap<Cidade, InfoCidade> getHashCidades() {
			return hashCidades;
		}
	}

	public class InfoCidade{
		private Cidade cidade;
		private Integer quantidadeTurmasAtivas=0;
		private Integer quantidadeTurmasInativas=0;
		private HashMap<Sexo, List<Aluno>> sexos=new HashMap<Sexo, List<Aluno>>();
		private HashMap<Turma, List<Voluntario>> voluntarios=new HashMap<Turma, List<Voluntario>>();
		private HashMap<Cor, List<Aluno>> cores=new HashMap<Cor, List<Aluno>>();
		private HashMap<Turma, List<Aluno>> alunosAtivos=new HashMap<Turma, List<Aluno>>();
		private HashMap<Turma, List<Aluno>> alunosInativos=new HashMap<Turma, List<Aluno>>();


		public InfoCidade(Cidade cidade) {
			this.cidade=cidade;

			for(Sexo sexo:Sexo.values()){
				sexos.put(sexo, new ArrayList<Aluno>());
			}

			for(Cor cor:Cor.values()){
				cores.put(cor, new ArrayList<Aluno>());
			}

			Set<Turma> turmas=cidade.getTurmas();

			for(Turma turma:turmas){
				voluntarios.put(turma, new ArrayList<Voluntario>());
				if(turma.isAtivo()){
					alunosAtivos.put(turma, new ArrayList<Aluno>());
					quantidadeTurmasAtivas++;
				}
				else{
					alunosInativos.put(turma, new ArrayList<Aluno>());
					quantidadeTurmasInativas++;
				}


			}

		}



		public void add(Turma turma,Aluno aluno){
			sexos.get(aluno.getSexo()).add(aluno);
			cores.get(aluno.getCor()).add(aluno);
			if(turma.isAtivo())
				alunosAtivos.get(turma).add(aluno);
			else
				alunosInativos.get(turma).add(aluno);

		}
		public void add(Turma turma,Voluntario voluntario){
			voluntarios.get(turma).add(voluntario);
		}


		public Cidade getCidade() {
			return cidade;
		}
		public void setCidade(Cidade cidade) {
			this.cidade = cidade;
		}
		public HashMap<Sexo, List<Aluno>> getSexos() {
			if(sexos==null)
				sexos=new HashMap<Sexo, List<Aluno>>();
			return sexos;
		}
		public void setSexos(HashMap<Sexo, List<Aluno>> sexos) {
			this.sexos = sexos;
		}
		public HashMap<Turma, List<Voluntario>> getVoluntarios() {
			if(voluntarios==null)
				voluntarios=new HashMap<Turma, List<Voluntario>>();
			return voluntarios;
		}
		public void setVoluntarios(HashMap<Turma, List<Voluntario>> voluntarios) {
			this.voluntarios = voluntarios;
		}
		public HashMap<Cor, List<Aluno>> getCores() {
			if(cores==null)
				cores=new HashMap<Cor, List<Aluno>>();
			return cores;
		}
		public void setCores(HashMap<Cor, List<Aluno>> cores) {
			this.cores = cores;
		}

		public HashMap<Turma, List<Aluno>> getAlunosAtivos() {
			return alunosAtivos;
		}

		public HashMap<Turma, List<Aluno>> getAlunosInativos() {
			return alunosInativos;
		}
		public void setAlunosInativos(HashMap<Turma, List<Aluno>> alunosInativos) {
			this.alunosInativos = alunosInativos;
		}

		public void setAlunosAtivos(HashMap<Turma, List<Aluno>> alunos) {
			this.alunosAtivos = alunos;
		}

		public Integer getHomens(){
			return sexos.get(Sexo.MASCULINO).size();
		}

		public Integer getMulheres(){
			return sexos.get(Sexo.FEMININO).size();
		}

		public Integer getQuantidadeAlunos(){
			return getHomens()+getMulheres();
		}


		public Integer getQuantidadeTurmasAtivas() {
			return quantidadeTurmasAtivas;
		}

		public Integer getQuantidadeTurmasInativas() {
			return quantidadeTurmasInativas;
		}

		private RelatorioCurso getOuterType() {
			return RelatorioCurso.this;
		}


		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + getOuterType().hashCode();
			result = prime * result
					+ ((cidade == null) ? 0 : cidade.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			InfoCidade other = (InfoCidade) obj;
			if (!getOuterType().equals(other.getOuterType()))
				return false;
			if (cidade == null) {
				if (other.cidade != null)
					return false;
			} else if (!cidade.equals(other.cidade))
				return false;
			return true;
		}
	}

}
